#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <wait.h>
#include <signal.h>
#include <string.h>


//The main work routine
void generateRandomNumbers();  
void ALARMhandler(int sig);

long long int count; //Will hold the count of how many of the random numbers were between 90-110

pid_t children[10]; //Create an array to hold the PIDs of all child processes so we can wait for them and print their exit status. I chose a size of 10 since most current systems don't have more than 10 processors.

   



/* The main work routine */


void generateRandomNumbers()  
{
    long long int i; //Variable for looping
    int randomNumber; //Variable to hold a random number 
    
    
    count = 0; //Make sure count starts at 0
    
    //Seed the random number generator with the process ID of the current child
    srandom(getpid());
	
    for (i = 0; i <= 300000000; i++) { //Generate 300 Million Random Numbers
		randomNumber = random();
		
		if(randomNumber > 90 && randomNumber < 110){
		  count++; //Increment the count
		}
  	}
  	
   
}

void  ALARMhandler(int sig){
  int i; //Looping Variable
  int cpuCount;
  cpuCount = sysconf(_SC_NPROCESSORS_CONF);
  printf("Received alarm signal!\n");
  //Kill all child processes
  for(i = 0; i < cpuCount; i++){  
    kill(children[i], SIGKILL);
  }
}


int main(int argc, char **argv)
{
    pid_t pid; //Create pid handle variable
    
    int cpuCount; //Holds the number of processors on the current system
    
    cpuCount = sysconf(_SC_NPROCESSORS_CONF); //Finds and sets the number of processors on this system
    
    int alarmInterval; //Create variable for the alarm interval passed as an argument
    
   
    
    
        
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <alarm interval>\n" ,argv[0]);
        exit(1);
    }
    
    
    alarmInterval = atoi(argv[1]); //Convert to integer
    
    //Set the alarm!
    
    signal(SIGALRM, ALARMhandler); //Create the signal handler
    alarm(alarmInterval); //Set the alarm
    
   
    
    printf("original process, pid = %d\n",getpid());

   //Create the processes.
    
      
    //Create variables and start the loop
    
    int i; //Looping Variable   
        
    
    for(i = 0; i < cpuCount; i++){
	if ((pid = children[i] = fork()) < 0){
	  printf("fork error for child %d\n",i);
	}
	else if (pid == 0){ //If this is the child process running
	  int c; //Variable for looping
	  printf("child %d, pid = %d\n",i,getpid());
	  for(c = 0; c > -1;c++){ //Creates an infinite loop since "c" is always greater than -1
	    generateRandomNumbers();
	    printf("Process %d finished round %d count = %lld\n",getpid(),c,count);
	    sleep(5);
	  }
	  //NOTE: We don't need to put an "exit()" command here to end the child process because the above
	  //for-loop is infinite so it would never make it this far anyway. The alarm signal handler will handle
	  //killing this process after the alarm time interval is up. If this was a regular child process with no infinite-loop
	  //then we would need to put an "exit()" command here so that our child process wouldn't just linger
	  //in the background forever after it's done executing its commands.
	}
	
    }
    
    
    
    
   //Wait for child processes to be killed by the alarm signal handler then print their exit status 
   for (i = 0; i < cpuCount; i++){
       int status;
       waitpid(children[i], &status, 0);
       printf("pid = %d child %d killed with signal %d (%s)\n", children[i], i, status, strsignal(status));
   }
    

    exit(0);
}
